﻿
using System;

using System.Text;

using System.Windows.Forms;

using System.Management;
using Valentia.Kinection.DataTypes;

namespace Valentia.Kinection.Watchdog
{
    /// <summary>
    /// Class monitors Kinect device
    /// </summary>
    internal class KinectWatchDog : IDisposable
    {
        #region Declarations
        private String kinectionServiceName = "Valentia Kinection Service";
        private ManagementEventWatcher managementEventWatcher;
        #endregion

        #region Internal Methods

        /// <summary>
        /// Subscribes to temporary event notifications based on a 
        /// USB device controller event query.
        /// </summary>
        internal void Start()
        {

            WqlEventQuery q;
            ManagementOperationObserver observer = new ManagementOperationObserver();

            // Bind to local machine
            ManagementScope scope = new ManagementScope("root\\CIMV2");

            //sets required privilege
            scope.Options.EnablePrivileges = true;

            q = new WqlEventQuery();
            q.EventClassName = "__InstanceOperationEvent";
            q.WithinInterval = new TimeSpan(0, 0, 3);
            q.Condition = @"TargetInstance ISA 'Win32_USBControllerDevice'";

            Console.WriteLine(q.QueryString);
            this.managementEventWatcher = new ManagementEventWatcher(scope, q);

            this.managementEventWatcher.EventArrived += new EventArrivedEventHandler(managementEventWatcher_EventArrived);
            this.managementEventWatcher.Start();

            Logger.Log("Management watcher started");
        }

        /// <summary>
        /// Occurs when subscribed event notifications generated
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Event Args</param>
        internal void managementEventWatcher_EventArrived(object sender, EventArrivedEventArgs e)
        {
            try
            {
                //Get the Event object and display it
                foreach (PropertyData pd in e.NewEvent.Properties)
                {
                    ManagementBaseObject mbo = null;
                    if ((mbo = pd.Value as ManagementBaseObject) != null)
                    {
                        foreach (PropertyData prop in mbo.Properties)
                        {
                            if (prop.Value != null)
                                //Checking Kinect device id
                                if (prop.Value.ToString().Contains(@"VID_045E&PID_02B0"))
                                {
                                    System.Threading.Thread.Sleep(10000);
                                    //Restart Service here

                                    Logger.Log("Management event detected for property: {0} with value: {1}", prop.Name, prop.Value.ToString());

                                    System.ServiceProcess.ServiceController cntrl = new System.ServiceProcess.ServiceController(this.kinectionServiceName);
                                    Logger.Log("Stopping kinection service");
                                    try
                                    {
                                        cntrl.Stop();
                                    }
                                    catch { }

                                    while (cntrl.Status != System.ServiceProcess.ServiceControllerStatus.Stopped)
                                    {
                                        //cntrl = cntrl;
                                        cntrl.Refresh();
                                    }
                                    Logger.Log("Starting kinection service");
                                    try
                                    {
                                        cntrl.Start();
                                    }
                                    catch { }


                                    while (cntrl.Status != System.ServiceProcess.ServiceControllerStatus.Running)
                                    {
                                        cntrl.Refresh();
                                    }

                                    Logger.Log("Kinection service started");
                                }
                        }
                    }
                }
            }
            catch (Exception exp) { Logger.Log(exp, "Exception in ManagementWatcherEvent handler"); }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Free resources
        /// </summary>
        public void Dispose()
        {
            { try { this.managementEventWatcher.Dispose(); } catch { } }
            Logger.Log("Management watcher stopped");
        }

        #endregion
    }
}